﻿using System;
using System.Linq;
using Reactor.Environment;
using Reactor.Messages.Commands.Core;
using Reactor.Messaging;
using Reactor.Messaging.Attributes;
using Reactor.Providers;
using Reactor.Resources;
using Reactor.ServiceGrid;

namespace Reactor.CoreHost.Handlers
{
    [PointToPointChannel]
    public class OrphanServiceCommandHandler : MessageHandlerBase<OrphanService>
    {
        #region Overrides of MessageHandlerBase<OrphanService>

        public override void OnHandling(OrphanService message, IMessageContext messageContext)
        {
            // Ensure message is valid
            if (string.IsNullOrEmpty(message.ServiceName)) throw new InvalidOperationException("No service name provided.");
            if (string.IsNullOrEmpty(message.ServiceVersion)) throw new InvalidOperationException("No service version provided.");

            AssertThatCurrentServiceIsAReactorCore();

            var core = (IReactorCore) Context.GridContext.CurrentReactorService;

            // Ensure message is for this Core
            if(message.CoreName != core.Identifier.Name)
            {
                Log.WarnFormat("Received OrphanService command but cannot process it because it was destined for another Core named: {0}", message.CoreName);
                return;
            }

            // Find service instance identifier for this service name/version
            var instanceIdentifier = GetInstanceIdentifierForService(message.ServiceName, message.ServiceVersion, core.Identifier);

            try
            {
                // Instruct core to orphan this service
                core.OrphanService(new ServiceIdentifier {Name = message.ServiceName, Version = new Version(message.ServiceVersion)},  instanceIdentifier);
            }
            catch (InvalidOperationException e)
            {
                Log.Error("ReactorCore threw an exception when OrphanService was called.", e);
            }
        }

        private static Guid GetInstanceIdentifierForService(string serviceName, string serviceVersion, ServiceIdentifier coreIdentifier)
        {
            var coreDataProvider = Context.ServiceLocator.GetInstance<ICoreDataProvider>();
            if(coreDataProvider == null)
                throw new InvalidOperationException(CommonResources.Error_CannotLocateCoreDataProvider);

            var services = coreDataProvider.GetAllServiceInstancesAssignedToCore(coreIdentifier);
            return (from s in services
                    where s.Identifier.Name == serviceName && s.Identifier.Version.ToString() == serviceVersion
                    select s.InstanceIdentifier).FirstOrDefault();
        }

        #endregion
    }
}
